import { CancelToken } from 'axios';
import { uploadChunk, mergeChunks, checkFileStatus as checkFileStatusApi } from '@/api/upload';

class FileUploader {
  constructor() {
    this.CHUNK_SIZE = 5 * 1024 * 1024; // 5MB
  }

  // 生成文件哈希（使用时间戳和随机数 每次hash都不一致，同一文件可多次上传，无法断点续传）
  async calculateFileHash(file) {
    return new Promise((resolve) => {
      // 使用更安全的方式生成文件标识
      const timestamp = Date.now();
      const random = Math.random().toString(36).substring(2, 15);
      const fileInfo = `${file.name}-${file.size}-${timestamp}-${random}`;
      
      // 安全的 Base64 编码
      const safeBase64 = btoa(unescape(encodeURIComponent(fileInfo)))
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
      
      resolve(safeBase64);
    });
  }

  // 更精确的文件哈希计算（使用文件内容）同一文件hash值不变，可断点续传
  async calculateFileHashByContent(file) {
    return new Promise((resolve) => {
      const chunkSize = 64 * 1024; // 64KB
      const chunks = Math.ceil(file.size / chunkSize);
      const hashChunks = [];
      let currentChunk = 0;

      const readNextChunk = () => {
        const start = currentChunk * chunkSize;
        const end = Math.min(start + chunkSize, file.size);
        const chunk = file.slice(start, end);

        const reader = new FileReader();
        reader.onload = (e) => {
          // 简单的哈希计算，实际生产环境可以使用更复杂的算法
          const arrayBuffer = e.target.result;
          const uint8Array = new Uint8Array(arrayBuffer);
          
          let hash = 0;
          for (let i = 0; i < uint8Array.length; i++) {
            hash = ((hash << 5) - hash) + uint8Array[i];
            hash = hash & hash; // Convert to 32bit integer
          }
          
          hashChunks.push(hash.toString(36));
          currentChunk++;

          if (currentChunk < chunks) {
            readNextChunk();
          } else {
            // 合并所有块的哈希
            const finalHash = hashChunks.join('') + '-' + file.size + '-' + Date.now();
            const safeHash = btoa(unescape(encodeURIComponent(finalHash)))
              .replace(/\+/g, '-')
              .replace(/\//g, '_')
              .replace(/=/g, '');
            resolve(safeHash.substring(0, 32)); // 限制长度
          }
        };

        reader.onerror = () => {
          // 如果内容读取失败，回退到简单哈希
          resolve(this.calculateSimpleHash(file));
        };

        reader.readAsArrayBuffer(chunk);
      };

      readNextChunk();
    });
  }

  // 简单的哈希生成（备用方案）
  async calculateSimpleHash(file) {
    const timestamp = Date.now();
    const random = Math.random().toString(36).substring(2, 15);
    const fileInfo = `${file.name}-${file.size}-${timestamp}-${random}`;
    
    // 安全的 Base64 编码
    const safeBase64 = btoa(unescape(encodeURIComponent(fileInfo)))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '');
    
    return safeBase64.substring(0, 32);
  }

  // 文件分片
  createFileChunks(file) {
    const chunks = [];
    let cur = 0;
    while (cur < file.size) {
      chunks.push(file.slice(cur, cur + this.CHUNK_SIZE));
      cur += this.CHUNK_SIZE;
    }
    return chunks;
  }

  // 上传分片
  async uploadChunk(chunkData, onProgress) {
    const formData = new FormData();
    formData.append('chunk', chunkData.chunk);
    formData.append('hash', chunkData.hash);
    formData.append('index', chunkData.index.toString());
    formData.append('fileHash', chunkData.fileHash);
    formData.append('chunkSize', this.CHUNK_SIZE.toString());
    formData.append('fileName', chunkData.fileName);

    try {
      const response = await uploadChunk(formData, {
        onUploadProgress: (progressEvent) => {
          if (onProgress && progressEvent.total) {
            const progress = (progressEvent.loaded / progressEvent.total) * 100;
            onProgress(progress);
          }
        },
        timeout: 60000,
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      });
      return response.data;
    } catch (error) {
      console.error('分片上传失败:', error);
      throw new Error(`分片 ${chunkData.index + 1} 上传失败: ${error.message}`);
    }
  }

  // 合并文件
  async mergeChunks(fileHash, fileName, totalChunks) {
    try {

      const response = await mergeChunks({
        fileHash,
        fileName: this.safeFileName(fileName),
        totalChunks,
        chunkSize: this.CHUNK_SIZE
      }, {
        timeout: 30000
      });
      return response;
    } catch (error) {
      console.error('文件合并失败:', error);
      throw new Error(`文件合并失败: ${error.message}`);
    }
  }

  // 检查文件状态（用于断点续传）
  async checkFileStatus(fileHash, fileName, totalChunks) {
    try {
      const response = await checkFileStatusApi(
        { 
          fileHash, 
          fileName: this.safeFileName(fileName),
          totalChunks
        },
        {
          timeout: 10000
        }
      );
      return response;
    } catch (error) {
      console.error('检查文件状态失败:', error);
      return { exists: false, uploadedChunks: [] };
    }
  }

  // 安全的文件名处理
  safeFileName(fileName) {
    // 移除特殊字符，只保留字母数字、中文、下划线和点
    return fileName.replace(/[^\w\u4e00-\u9fa5.-]/g, '_');
  }

  // 取消上传
  createCancelToken() {
    return CancelToken.source();
  }

  // 保存上传进度到本地存储(断点续传)
  saveProgressToLocal(fileHash, progress) {
    try {
      const progressData = {
        fileHash,
        fileName: progress.fileName,
        uploadedChunks: progress.uploadedChunks,
        totalChunks: progress.totalChunks,
        timestamp: Date.now()
      };
      localStorage.setItem(`upload_progress_${fileHash}`, JSON.stringify(progressData));
    } catch (error) {
      console.warn('保存进度到本地存储失败:', error);
    }
  }

  // 从本地存储加载上传进度(断点续传)
  loadProgressFromLocal(fileHash) {
    try {
      const saved = localStorage.getItem(`upload_progress_${fileHash}`);
      return saved ? JSON.parse(saved) : null;
    } catch (error) {
      console.warn('从本地存储加载进度失败:', error);
      return null;
    }
  }

  // 清理本地存储的进度
  clearProgressFromLocal(fileHash) {
    try {
      localStorage.removeItem(`upload_progress_${fileHash}`);
    } catch (error) {
      console.warn('清理本地存储进度失败:', error);
    }
  }
}

export default FileUploader;